﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Diagnostics;
using System.Threading;
using MahApps.Metro;
using MahApps.Metro.Controls;

namespace DConsole
{
    /// <summary>
    /// Interaction logic of MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        /// <summary>
        /// The limit of lines in the history box.
        /// </summary>
        private int _HistoryLinesLimit = 100;

        /// <summary>
        /// The Cmd core process.
        /// </summary>
        private Process _CmdProcess = null;


        /// <summary>
        /// The handler for output data received event.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The received data.</param>
        private void _OutputDataReceivedEventHandler(object sender, DataReceivedEventArgs e)
        {
            // Catch directory information
            if (e.Data.Length >= 4
                && e.Data[1] == ':'
                && e.Data[2] == '\\'
                && e.Data[e.Data.Length - 1] == '>')
            {
                lblCurrentPath.Dispatcher.Invoke(new Action(() => { lblCurrentPath.Content = e.Data; }));
                return;
            }

            // Receive command result
            if (!String.IsNullOrEmpty(e.Data)) txtHistory.Dispatcher.Invoke(new Action(() => { txtHistory.Text += e.Data + Environment.NewLine; }));
        }


        /// <summary>
        /// Instantiate an object of MainWindow class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            // Configure Cmd process
            _CmdProcess = new Process();
            _CmdProcess.StartInfo.FileName = "cmd.exe";
            _CmdProcess.StartInfo.CreateNoWindow = true;
            _CmdProcess.StartInfo.RedirectStandardInput = true;
            _CmdProcess.StartInfo.RedirectStandardOutput = true;
            _CmdProcess.StartInfo.UseShellExecute = false;
            _CmdProcess.OutputDataReceived += new DataReceivedEventHandler(_OutputDataReceivedEventHandler);

            // Run process
            _CmdProcess.Start();
            _CmdProcess.BeginOutputReadLine();

            // Catch initial directory
            _CmdProcess.StandardInput.WriteLine();
        }


        // Trigger: history text changed
        private void txtHistory_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            // Trim overflow buffer
            if (txtHistory.LineCount > _HistoryLinesLimit)
            {
                txtHistory.Text = txtHistory.Text.Substring(txtHistory.GetCharacterIndexFromLineIndex(txtHistory.LineCount - _HistoryLinesLimit));
            }
            
            // Scroll to the end
            txtHistory.ScrollToEnd();
        }

        // Trigger: window closed
        private void MetroWindow_Closed(object sender, EventArgs e)
        {
            // Terminate the Cmd process
            _CmdProcess.CancelOutputRead();
            _CmdProcess.StandardInput.WriteLine("exit");
            _CmdProcess.WaitForExit();
            _CmdProcess.Close();
            
            // Shutdown the application ::  !!! TODO: background waiting
            Application.Current.Shutdown();
        }

        // Keyboard: press "ESC" on Window
        private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                this.Close();
            }
            else
            {
                txtCommand.Focus();
                txtCommand.Select(txtCommand.Text.Length, 0);
            }

            e.Handled = true;
        }

        // Keyboard: press "Enter" on Command Box
        private void txtCommand_KeyUp(object sender, KeyEventArgs e)
        {
            if(e.Key == Key.Escape)
            {
                txtHistory.Focus();
            }

            if (e.Key == Key.Enter)
            {
                // Append new line
                txtHistory.Text += Environment.NewLine;

                // Send command
                _CmdProcess.StandardInput.WriteLine(txtCommand.Text);
                txtCommand.Text = "";

                // Sending for directory re-check
                _CmdProcess.StandardInput.WriteLine();
            }

            e.Handled = true;
        }
    }
}
